package com.cskaoyan.javase.oop2._1extends._7initialization._1basic;

import java.util.SplittableRandom;

/**
 * 我们通过一个引例，练习来讲解这个问题：
 * 创建一个Person类，有name属性和eat方法
 * 创建一个Star类，有stageName属性和sing方法
 * Star类要继承Person类
 * 创建Star类对象，画出这个过程的内存图，描述子类对象初始化的过程。
 *
 * 以下是分析过程:
 * 1.既然要创建Star对象,首先要考虑类加载,那么该类有一个父类,会对类加载造成影响吗?
 *      会,Java代码中一旦碰到类加载子类的场景,就会优先进行父类的类加载
 *      类加载是"先父后子"的
 *
 * 2.创建子类对象,会不会创建父类对象?
 * 很明显不会,只会创建一个子类对象,并不会创建任何父类对象
 *
 * 3.既然只有一个子类对象,那么父类的成员变量放在哪里呢?
 * 肯定是放在子类对象当中,不会放在其它地方
 * 子类对象中会专门开辟一片独立的区域,用来存储父类的成员变量,
 * 而子类自身的成员仍会存储在自身对象当中
 *
 * 4.接下来最重要的就是研究子类对象中,父子类成员变量的赋值
 * 首先默认初始化是最先完成的,默认初始化是创建对象过程中,由JVM默认给成员变量一个默认值
 * 无需考虑默认初始化是如何进行的
 * 因为在任何能够看到的代码执行位置,默认值早就已经存在了
 *
 * 5.除了默认初始化,那么还剩下:
 *      a.显式赋值
 *      b.构造代码块赋值
 *      c.构造器赋值
 * 以上结构是如何执行的呢?
 * 按理说,应该"先父后子",实测下来也确实是"先父后子"的
 *
 * 6.子类对象成员变量赋值的"先父后子"到底是如何保证的呢?
 * 又是什么原理呢?
 * 父类当中有父类的赋值手段
 * 子类当中有子类的赋值手段
 * 在各自类中,它们各自结构的执行顺序,我们已经很熟练的
 * 那么如何保证父类的成员变量赋值手段都在子类的成员变量赋值手段之前执行呢?
 * 只要保证父类当中最后执行的结构---父类构造器
 * 先于子类当中任何结构执行
 * 就能够保证"先父后子"了
 *
 * 通过构造代码块父类先执行
 * 说明父类的构造器就是先于子类执行的
 * 这样子类对象当中,父子类成员变量的赋值就确实是"先父后子"的
 *
 * 7.构造器的执行为什么能够"先父后子"呢?
 * super关键字:
 * 指向子类对象中那片父类成员的区域,可以近似的看成super指向子类的父类对象(不是真的父类对象)
 *
 * 隐式子类对象初始化:
 *  在子类构造器中可以this表示调用自身构造器
 *  也可以用super表示调用父类构造器
 *  实际上,
 *  在Java的任何一个类中的任何一个构造器中,
 *  如果该构造器的第一行没有this或者super
 *  直接去调用其他构造器
 *  那么就永远隐含一句"super()"
 *  表示调用父类的无参构造器
 *  隐式初始化,只会调用父类的无参构造器,不能完成父类成员变量赋值
 *  所以如果想要赋值就要明确的调用父类的有参构造器
 *  这就是显式子类对象初始化
 *
 * 显式子类对象初始化
 * 在子类构造器的第一行,用super(实参)明确表示调用父类构造器
 * 这就是显式子类对象初始化
 *
 * @since 09:55
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // Star s = new Star();
        // System.out.println(s.stageName);
        Star s2 = new Star("张三");
        System.out.println(s2.name);
        System.out.println(s2.stageName);

        Star s3 = new Star("李四", "麻子");
        System.out.println(s3.stageName);
        System.out.println(s3.name);

    }
}

class Person {
    /*static {
        System.out.println("person类加载了");
    }*/
    String name = "大耳朵图图";
    /*{
        System.out.println("Person的构造器执行了!");
    }*/

    public Person(String name) {
        this.name = name;
    }

    public Person() {
        System.out.println("Person");
    }

    public void eat() {
        System.out.println("为了学习,可以不吃饭!");
    }
}

class Star extends Person {
    /*static {
        System.out.println("star类加载了");
    }*/

    /*{
        System.out.println("Star的构造器执行了!");
    }*/

    // 艺名
    String stageName = name + "的🐮👴";

    public Star() {
        // 隐含super() 调用父类无参
        System.out.println("Son");
    }

    public Star(String name) {
        // 子类对象显示初始化
        super(name);
    }

    public Star(String name, String stageName) {
        super(name);
        this.stageName = stageName;
    }

    public void sing() {
        System.out.println("爱的供养!");
    }
}